/**
	@file nicojk.js
	@brief ニコニコ実況のサイトで有効になってほしいjsファイル。
	@date 2011/12/31
	@author satmat
	winter.daydreams@gmail.com
	twitter: satellitesat
*/
var SATMAT_NICOJK = SATMAT_NICOJK || {};



/**
	@brief 名前空間の生成関数
*/
SATMAT_NICOJK.namespace = function (ns_string){
	var parts = ns_string.split('.'),
		parent = SATMAT_NICOJK,
		i,
		max;
		
	if(parts[0] === "SATMAT_NICOJK") {
		parts = parts.slice(1);
	}
	
	for(i=0, max=parts.length; i<max; i+= 1){
		if(typeof parent[parts[i]] === "undefined"){
			parent[parts[i]] = {};
		}
		parent = parent[parts[i]];
	}
	return parent;
}


/**
	@brief コメントバッファの生成。ただのObjectの配列。
*/
SATMAT_NICOJK.namespace('SATMAT_NICOJK.Nicojk.CommentBuffer');
SATMAT_NICOJK.Nicojk.CommentBuffer = [];


/**
	@brief コメント再生プレイヤ
*/
SATMAT_NICOJK.namespace('SATMAT_NICOJK.player');
SATMAT_NICOJK.player = (function(){

	var fps = 30,
		timer_interval = 0,
		event_start_date = 0,
		channel_name = "",
		
	timer_interval = Math.round(1000/fps);

	return {
		FPS: fps,
		COMMENT_VISIBLE_TIME: 4000,			// [ms]
		TIMER_INTERVAL: timer_interval,		// [ms]
		event_start_date: 0, 	// [ms]
		event_end_date: 0, 	// [ms]
		timer_count: 0,
		play_start_date_obj: new Date(),
 		play_elapsed_time: 0,
 		play_past_time: 0,
 		play_interval_time: timer_interval, // 1タイマカウントごとに進むべき時間[ms]。初期値はタイマインターバルと同じ(1倍速)。
 		comment_count: 0,
 		last_comment_number: 0,
 		timer_id: 0,
 		
 		getTimerInterval: function(){		// [ms]
 			return 1000/fps;
 		},
 			 		
 		startTimer: function(){
			var player = SATMAT_NICOJK.player;
			if(!player.timer_id){
 				player.timer_id = setInterval(player.scroll, player.getTimerInterval());
			}
 		},
 		
 		stopTimer: function(){
			var player = SATMAT_NICOJK.player;
			if(player.timer_id){
				clearInterval(player.timer_id);
				player.timer_id = 0;
			}
 		},
 		
 		toggleTimer: function(event){
			var player = SATMAT_NICOJK.player;
			if(player.timer_id){
				player.stopTimer();
			}else{
				player.startTimer();
			}
 		},
 		
 		/**
 			ratio: 倍率。1.5倍速など。
 		*/
// 		setPlayInterval: function(event){
//			var player = SATMAT_NICOJK.player,
//				ratio = document.getElementById('play_ratio').value;
//			
//			player.play_interval_time = (ratio*1000)/fps;
//		},
		
//		replay: function(event){
//			var player = SATMAT_NICOJK.player;
//		
//			player.play_past_time = player.event_start_date;
//			player.play_elapsed_time = 0;
//			player.comment_count = 0;
//			player.last_comment_number = 0;
//		},
		
// 		changePosition: function(event, offset){
//			var player = SATMAT_NICOJK.player;
//	
//			player.play_past_time = player.play_past_time + offset;
//			player.play_elapsed_time = player.play_elapsed_time + offset;
//			player.comment_count = 0;
//			player.last_comment_number = 0;
//		},
 			 		
		init: function(cmtbuf, start_time, end_time){
			var player = SATMAT_NICOJK.player;
			
			player.comment_buffer = cmtbuf;
			player.event_start_date = start_time*1000; // [ms]
			player.event_end_date = end_time; // [ms]
			play_past_time = start_time*1000;
			player.canvas = document.getElementById('external_player');
			player.ctx = player.canvas.getContext('2d');
 			player.stat_div = document.getElementById('stat_div');			
			player.startTimer();
		},
		
		scroll: function(){
			var player = SATMAT_NICOJK.player,
				cntmng = SATMAT_NICOJK.Nicojk.ConnectionManager,
				now = new Date(),
				datestr = 0,
				timestr = 0,
				ctx = player.ctx,
				canvas = player.canvas,
				mblen = player.comment_buffer.length,
				i = 0,
				viewnum = 0;
				
	
			/* 黒背景 */
			ctx.fillStyle = 'black';		
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			
			/* チャンネル名 */
			if(cntmng && cntmng.getFlvinfo()){
				channel_name = cntmng.getFlvinfo().channel_name;
			
				ctx.fillStyle = '#6af422';
				ctx.font = '32pt';
				ctx.fillText(channel_name, 20, 30);
			}
			
			/* 日時 */
			player.play_elapsed_time += player.play_interval_time;
			player.play_past_time = player.event_start_date + player.play_elapsed_time;
			
			datestr = player.date2str(player.msec2date(player.play_past_time));
			timestr = player.time2str(player.msec2date(player.play_past_time));

			ctx.fillStyle = '#535353'; // 濃いグレー
			ctx.font = '48pt Arial';
			ctx.fillText(datestr, 100, 180);
			
			ctx.font = '36pt Arial';
			ctx.fillText(timestr, 170, 230);
			
			/* コメント */
			ctx.fillStyle = 'white';
			ctx.font = "18pt Arial bold";
							
			// メッセージバッファ中からコメントを選択
			for(i=0; i<mblen; i++){
				var text_metrics = 0,
					speed_x = 0,
					text_x = 0,
					text_y = 0,
					comment_elem = {};
					
				comment_elem = player.comment_buffer[i];
				if(comment_elem.date*1000 <= player.play_past_time
					&& player.play_past_time < comment_elem.date*1000 + player.COMMENT_VISIBLE_TIME){
											
					text_metrics = ctx.measureText(comment_elem.textContent);
					speed_x = (player.canvas.width + text_metrics.width).toFixed(1)/player.COMMENT_VISIBLE_TIME; // ミリ秒あたりの移動時間
					text_x = player.canvas.width - Math.round(speed_x*(player.play_past_time - comment_elem.date*1000));
					if(!comment_elem.textHeight){
						text_y = (30*(viewnum+1))%player.canvas.height;
						comment_elem.textHeight = text_y;
					}
					if(text_x > -text_metrics.width){
						ctx.fillText(comment_elem.textContent, text_x, comment_elem.textHeight);
						viewnum++;
					}
					
					if(player.last_comment_number<comment_elem.no){
						player.last_comment_number = comment_elem.no;
						player.comment_count++;
					}
					
				}
				
			}
			
			SATMAT_NICOJK.Nicojk.main.setStatus();						
			player.timer_count++;
		},
		
		setChannelName: function(name){
			channel_name = name;
			return true;
		},
		
		date2str: function(date){
	 		var year = date.getFullYear(),
	 			month = date.getMonth(),
	 			day = date.getDate();
	 		
	 		month++;
	 		
	 		if(month<10){
	 			month = '0' + month;
	 		}
	 		
	 		if(day<10){
	 			day = '0' + day;
	 		}
	 		
	 		return year + '/' + month + '/' + day;
	 	},
	 	
	 	time2str: function(time){
	 		var hour = time.getHours(),
		 		min = time.getMinutes(),
		 		sec = time.getSeconds();
		 		
	 		if(hour<10){
	 			hour = '0' + hour;
	 		}
	 		if(min<10){
	 			min = '0' + min;
	 		}
	 		if(sec<10){
	 			sec = '0' + sec;
	 		}
	 		return hour + ':' + min + ':' + sec;
	 	},
	 	
	 	msec2date: function(msectime){
	 			var dateobj = new Date();
	 		
	 		dateobj.setTime(msectime);
	 		return dateobj;
	 	},
	 	
	 	msec2dateYmdStr: function(msectime){
	 		var player = SATMAT_NICOJK.player,
	 			dateObj = {},
	 			dateStr = "",
	 			timeStr = "";
	 				 		
	 		dateObj = player.msec2date(msectime);
	 		dateStr = player.date2str(dateObj);
	 		timeStr = player.time2str(dateObj);

	 		return dateStr + " " + timeStr;
	 	}
	 	
	}
}());


/**
	@brief 接続管理
*/
SATMAT_NICOJK.namespace("SATMAT_NICOJK.Nicojk.ConnectionManager");
SATMAT_NICOJK.Nicojk.ConnectionManager = (function(){
	var NICOJK_GETFLV_QUERY_BASE_URL = "http://jk.nicovideo.jp/api/v2/getflv?v=",
		NICOJK_GETTHREADFORCES_QUERY_BASE_URL = "http://jk.nicovideo.jp/api/v2/getthreadforces?thread_id=",
		NICOJK_GETWAYBACKKEY_QUERY_BASE_URL = "http://jk.nicovideo.jp/api/v2/getwaybackkey?thread=",		
		queryString2Array = null,
		livegetflv = null,
		loggetflv = null,
		getflv = null,
		getThreadforces = null,
		getWaybackkey = null,
		liveGetcomment = null,
		jkinfo = {},
		flvinfo = {},
		waybackkey = "",
		threadinfo = {},
		threadforces = "",
		message_buffer = [],
		last_chat_no = 0,
		log_get_begin_time = 0,
		live_res_from_num = "-16",
		log_res_from_num = "-1000",
		live_comment_req_interval = 1000,	// [ms]
		log_comment_req_interval = 40*1000, // [ms]
		timer_id = 0;
				
		jkinfo.jknum = "";
		jkinfo.log_start_time = "";		/* 再生開始基準となるログの時刻 */
		jkinfo.log_end_time = "";		/* 再生終了基準となるログの時刻(設定しておくが使いどころが無い) */
		
		flvinfo.getflvParamArray = "";
		flvinfo.thread_id = "";
		flvinfo.ms = "";
		flvinfo.http_port = "";
		flvinfo.channel_no = "";
		flvinfo.channel_name = "";
		flvinfo.thread_base_time = "";
		flvinfo.thread_open_time = "";
		flvinfo.thread_start_time = "";
		flvinfo.thread_end_time = "";
		flvinfo.user_id = "";
		flvinfo.threadforces = "";
		
		threadinfo.resultcode = -1;
		threadinfo.thread = 0;
		threadinfo.last_res = 0;
		threadinfo.ticket = "";
		threadinfo.revision = 0;
		threadinfo.server_time = 0;
				
	livegetflv = function(){
		var query = NICOJK_GETFLV_QUERY_BASE_URL + jkinfo.jknum;

		getflv(query);
		return true;
	};
	
	loggetflv = function(){
		var query = NICOJK_GETFLV_QUERY_BASE_URL + jkinfo.jknum
		+ '&start_time=' + jkinfo.log_start_time + 
		+ '&end_time=' +  jkinfo.log_end_time;
		
		getflv(query);
		return true;
	};
	
	/**
		@brief ニコニコAPIのgetflvを実行し、スレッド情報を取得。
	*/
	getflv = function(query){
		var xhr = null;
	
		console.log('getflv query: '+query);
		
		xhr = new XMLHttpRequest();
		xhr.open('GET', query, false);
		xhr.send();
		
		if(xhr.readyState === 4){
			if(xhr.status === 200){
				console.log(xhr.responseText);
				flvinfo.getflvParamArray = queryString2Array(xhr.responseText);
				if(flvinfo.getflvParamArray){
					flvinfo.thread_id = flvinfo.getflvParamArray['thread_id'];
					flvinfo.ms = flvinfo.getflvParamArray['ms'];
					flvinfo.http_port = flvinfo.getflvParamArray['http_port'];
					flvinfo.channel_no = flvinfo.getflvParamArray['channel_no'];
					flvinfo.channel_name = decodeURIComponent(flvinfo.getflvParamArray['channel_name']);
					flvinfo.thread_base_time = parseInt(flvinfo.getflvParamArray['base_time']);
					flvinfo.thread_open_time = parseInt(flvinfo.getflvParamArray['open_time']);
					flvinfo.thread_start_time = parseInt(flvinfo.getflvParamArray['start_time']);
					flvinfo.thread_end_time = parseInt(flvinfo.getflvParamArray['end_time']);
					flvinfo.user_id = flvinfo.getflvParamArray['user_id'];
				}else{
					console.error('getflvparam malformed');
					return false;
				}
			}else{
				console.error(xhr.responseText);
				return false;
			}
		}
		return true;
	};
	
	
	/**
		@brief スレッドの勢い(getthreadforces)を取得
	*/
	getThreadforces = function(){
		var query = NICOJK_GETTHREADFORCES_QUERY_BASE_URL + flvinfo.thread_id,
			xhr = null;
		console.log(query);
	
		xhr = new XMLHttpRequest();
		xhr.open('GET', query, false);
		xhr.send();
		
		if(xhr.readyState === 4){
			if(xhr.status === 200){
				console.log(xhr.responseText);
				threadforces = xhr.responseText;
			}else{
				console.error('threadforces failed. http ' + xhr.status);
				console.error('following message is responseText.');
				console.error(xhr.responseText);
				return false;
			}
		}
		return true;
	};
	
	/**
		@brief 過去番組向け waybackkeyの取得
	*/
	getWaybackkey = function(){
		var xhr = new XMLHttpRequest(),
			query = "",
			waybackkeyarray = null,
			
	
		query = NICOJK_GETWAYBACKKEY_QUERY_BASE_URL + flvinfo.thread_id;	
		console.log("getwaybackkey query : "+ query);
		
		xhr.open('GET', query, false); // 同期
		xhr.send();
		
		if(xhr.readyState === 4){
			if(xhr.status === 200){
				waybackkeyarray = queryString2Array(xhr.responseText);
				
				waybackkey = waybackkeyarray["waybackkey"];
				if(!waybackkey || waybackkey == ""){
					console.error("malformed waybackkey");
					console.error("following message is responseText.");
					console.error(xhr.responseText);
				}
			}else{
				console.error('getwaybackkey failed. http ' + xhr.status);
				console.error('following message is responseText.');
				console.error(xhr.responseText);
			}
		}		
		return true;
	};
	
	/**
		@brief 現在番組向けコメント取得処理
	*/
	liveGetcomment = function(){
		var xhr = new XMLHttpRequest(),
			query = "";
	
		xhr.onreadystatechange = function (event) {
			if(xhr.readyState === 4){
				if(xhr.status === 200){
					var resXml = xhr.responseXML,
						threadTag = null,
						chatElems = null,
						i = 0,
						chatLen = 0,
						elem = null,
						no = 0;
					
					// スレッド情報の取得
					threadTag = resXml.getElementsByTagName('thread');
					if(threadTag.length == 0){
						console.error("There are no 'thread' tag.");
						return false;
					}
					
					if(!threadinfo){
						threadinfo = {};
					}
					
					if(threadTag[0].hasAttribute('resultcode')){
						threadinfo.resultcode = parseInt(threadTag[0].getAttribute('resultcode'));
					}
					if(threadTag[0].hasAttribute('thread')){
						threadinfo.thread = parseInt(threadTag[0].getAttribute('thread'));
					}
					if(threadTag[0].hasAttribute('last_res')){
						threadinfo.last_res = parseInt(threadTag[0].getAttribute('last_res'));
					}
					if(threadTag[0].hasAttribute('ticket')){
						threadinfo.ticket = threadTag[0].getAttribute('ticket');
					}
					if(threadTag[0].hasAttribute('revision')){
						threadinfo.revision = parseInt(threadTag[0].getAttribute('revision'));
					}				
					if(threadTag[0].hasAttribute('server_time')){
						threadinfo.server_time = parseInt(threadTag[0].getAttribute('server_time'));
					}
	
					chatElems = resXml.getElementsByTagName('chat');
					for(i=0, chatLen=chatElems.length; i<chatLen; i++){
						elem = {};
	
						if(chatElems[i].hasAttribute('no')){
							no = parseInt(chatElems[i].getAttribute('no'));
							if(last_chat_no>=no){ // 最終取得済みのチャット番号以下の場合は追加しない。
								continue;
							}
							elem.no = no;
							last_chat_no = no;
						}
						
						if(chatElems[i].hasAttribute('thread')){
							elem.thread = parseInt(chatElems[i].getAttribute('thread'));
						}
											
						if(chatElems[i].hasAttribute('vpos')){
							elem.vpos = parseInt(chatElems[i].getAttribute('vpos'));
						}
	
						if(chatElems[i].hasAttribute('date')){
							elem.date = parseInt(chatElems[i].getAttribute('date'));
						}
	
						if(chatElems[i].hasAttribute('mail')){
							elem.mail = chatElems[i].getAttribute('mail');
						}
						
						if(chatElems[i].hasAttribute('user_id')){
							elem.user_id = chatElems[i].getAttribute('user_id');
						}
	
						if(chatElems[i].hasAttribute('premium')){
							elem.premium = chatElems[i].getAttribute('premium');
						}
						
						if(chatElems[i].hasAttribute('anonymity')){
							elem.anonymity = chatElems[i].getAttribute('anonymity');
						}
						
						elem.textContent = chatElems[i].textContent;
						
						message_buffer.push(elem);
						
					}
				}else{
					console.error(xhr.responseText);
					SATMAT_NICOJK.Nicojk.ConnectionManager.stopLiveGetComment();
					return false;
				}
				
				SATMAT_NICOJK.Nicojk.main.setStaticStatus();
				
			}
		};
		
		if(!flvinfo.ms || flvinfo.ms=="" || 
			!flvinfo.http_port || flvinfo.http_port=="" || 
			!flvinfo.thread_id || flvinfo.thread_id=="" ||
			!live_res_from_num || live_res_from_num==""){
			
			console.error("malformed flvinfo.");
			return false;
		}
		
		query = 'http://'+flvinfo.ms+':'+flvinfo.http_port+'/api/thread?thread='+flvinfo.thread_id		
			+ '&res_from=' + live_res_from_num
			+ '&version=20061206';
	
		console.log('getcomment : ' + query);
	
		timer_id = setInterval(function(){
			console.log("setInteral request sent.");
			xhr.open('GET', query, true);
			xhr.send();
		}, live_comment_req_interval);
		
		return true;
	};
	
	logGetcomment = function(){
		var xhr = new XMLHttpRequest(),
			query = "",
			cmtmng = SATMAT_NICOJK.Nicojk.CommentManager,
			requestFunc = null;
		
		xhr.onreadystatechange = function (event) {
			if(xhr.readyState === 4){
				if(xhr.status === 200){
					var resXml = xhr.responseXML,
						threadTag = null,
						chatElems = null,
						i = 0,
						chatLen = 0,
						elem = null,
						no = 0;
					
					// スレッド情報の取得
					threadTag = resXml.getElementsByTagName('thread');
					if(threadTag.length == 0){
						console.error("There are no 'thread' tag.");
						return false;
					}
					
					if(!threadinfo){
						threadinfo = {};
					}
					
					if(threadTag[0].hasAttribute('resultcode')){
						threadinfo.resultcode = parseInt(threadTag[0].getAttribute('resultcode'));
					}
					if(threadTag[0].hasAttribute('thread')){
						threadinfo.thread = parseInt(threadTag[0].getAttribute('thread'));
					}
					if(threadTag[0].hasAttribute('last_res')){
						threadinfo.last_res = parseInt(threadTag[0].getAttribute('last_res'));
					}
					if(threadTag[0].hasAttribute('ticket')){
						threadinfo.ticket = threadTag[0].getAttribute('ticket');
					}
					if(threadTag[0].hasAttribute('revision')){
						threadinfo.revision = parseInt(threadTag[0].getAttribute('revision'));
					}				
					if(threadTag[0].hasAttribute('server_time')){
						threadinfo.server_time = parseInt(threadTag[0].getAttribute('server_time'));
					}
	
					chatElems = resXml.getElementsByTagName('chat');
					for(i=0, chatLen=chatElems.length; i<chatLen; i++){
						elem = {};
	
						if(chatElems[i].hasAttribute('no')){
							no = parseInt(chatElems[i].getAttribute('no'));
							if(last_chat_no>=no){ // 最終取得済みのチャット番号以下の場合は追加しない。
								continue;
							}
							elem.no = no;
							last_chat_no = no;
							log_res_from_num = no;
						}
						
						if(chatElems[i].hasAttribute('thread')){
							elem.thread = parseInt(chatElems[i].getAttribute('thread'));
						}
											
						if(chatElems[i].hasAttribute('vpos')){
							elem.vpos = parseInt(chatElems[i].getAttribute('vpos'));
						}
	
						if(chatElems[i].hasAttribute('date')){
							elem.date = parseInt(chatElems[i].getAttribute('date'));
						}
	
						if(chatElems[i].hasAttribute('mail')){
							elem.mail = chatElems[i].getAttribute('mail');
						}
						
						if(chatElems[i].hasAttribute('user_id')){
							elem.user_id = chatElems[i].getAttribute('user_id');
						}
	
						if(chatElems[i].hasAttribute('premium')){
							elem.premium = chatElems[i].getAttribute('premium');
						}
						
						if(chatElems[i].hasAttribute('anonymity')){
							elem.anonymity = chatElems[i].getAttribute('anonymity');
						}
						
						elem.textContent = chatElems[i].textContent;
						
						message_buffer.push(elem);	
					}					
				}else{
					console.error(xhr.responseText);
					SATMAT_NICOJK.Nicojk.ConnectionManager.stopLiveGetComment();
					return false;
				}
				
				SATMAT_NICOJK.Nicojk.main.setStaticStatus();
				
			}
		};
		
		log_get_begin_time = jkinfo.log_start_time + 50;
		
		request_func = function(){
			getWaybackkey();
			log_get_begin_time += log_comment_req_interval/1000;
			
			query = 'http://'+flvinfo.ms+':'+ flvinfo.http_port+'/api/thread?thread='+flvinfo.thread_id
				+ '&res_from=' + log_res_from_num
				+ '&version=20061206'
				+ '&when='+log_get_begin_time
				+ '&user_id='+flvinfo.user_id
				+ '&waybackkey=' + waybackkey;
				
			console.log(query);
			xhr.open('GET', query, true); // 非同期
			xhr.send();
			
			timer_id = setTimeout(request_func, log_comment_req_interval);
		};
		
		request_func();
		
/*
		if(get_start_time && get_start_time>0){
			// 関数引数が有効なとき、それを取得基準時刻にする。
			sttime = get_start_time + 50;
			// 取得開始数は最終レス番号とする。
			last = this.last_res;
			// waybackkeyの更新をする
			this.execGetwaybackkey();
			
		}else if(this.event_start_time){
			// 関数引数が無効なとき、番組の開始時刻+50秒を取得基準時刻にする。
			sttime = this.event_start_time + 50;
			// 番組開始時刻を基準に-1000個目を取得開始数とする
			last = this.LOG_RES_FROM_NUM_INIT;
		}else{
			console.log('get_start_time or event_start_time malformed.');
		}
		
		query = 'http://'+this.ms+':'+ this.http_port+'/api/thread?thread='+this.thread_id
			+ '&res_from=' + last
			+ '&version=20061206'
			+ '&when='+sttime
			+ '&user_id='+this.user_id
			+ '&waybackkey=' + this.waybackkey;
		console.log(query);
			
		xhr.open('GET', query, true); // 非同期
		xhr.send();
*/
			
		return true;
	}	
	
	/**
		@brief イコール(=)で結合されたクエリ文字列を、キーと値の連想配列（オブジェクト）に変換する。
		@param [in] クエリ文字列
		@retval クエリ文字列を連想配列に変換したオブジェクト
	*/
	queryString2Array = function(str){
		var qsplit = null,
			pair = null,
			qarray = new Array();
		
		if(!str){
			console.error("string is null.");
			return null;
		}
		
		qsplit = str.split('&');
		for(var i=0; qsplit.length>i; i++){
			pair = qsplit[i].split('=');
			if(pair[0] != ""){
				qarray[pair[0]] = decodeURIComponent(pair[1]);
			}
		}
		return qarray;
	};
				
	return {
	
		/**
			@brief jk番号、ログ開始時刻、ログ終了時刻をセットする。
			ログ終了時刻は使いどころがない。
		*/
		setjkinfo : function(jknum, starttime, endtime){
			jkinfo.jknum = jknum;
			jkinfo.log_start_time = starttime;
			jkinfo.log_end_time = endtime;
			return true;
		},
		
		/**
			@brief メッセージバッファのセット
		*/
		setMsgBuf : function(msgbuf){
			message_buffer = msgbuf;
			return true;
		},
		
		/**
			@brief
		*/
		stopLiveGetComment : function(){
			if(timer_id != 0){
				clearInterval(timer_id);
			}
			return true;
		},

		/**
			@brief
		*/
		getjkinfo : function(){
			return jkinfo;
		},
		
		/**
			@brief
		*/
		getFlvinfo : function(){
			return flvinfo;
		},
		
		/**
			@brief
		*/
		getThreadinfo : function(){
			return threadinfo;
		},
		
		/**
			@brief
		*/
		connectionStart : function(){
			livegetflv();
			getThreadforces();
			SATMAT_NICOJK.Nicojk.main.setStaticStatus();
			liveGetcomment();		
			return true;
		},
		
		/**
			@brief
		*/
		logConnectionStart : function(){
			loggetflv();
			getThreadforces();
			SATMAT_NICOJK.Nicojk.main.setStaticStatus();
			logGetcomment();		
			return true;		
		}
	}
	
}());



/**
	@brief ニコニコ実況Webページでの各種処理。
*/
SATMAT_NICOJK.namespace("SATMAT_NICOJK.Nicojk.main");
SATMAT_NICOJK.Nicojk.main = (function(){

	return {
		
		/**
			@brief ニコニコ実況Webページにおける初期処理。
		*/
		initializeOnNicojk: function(){
			var main = SATMAT_NICOJK.Nicojk.main;
		
			if(main.isLog() || main.isLive()){
				var phead = null,
					extPlayerLink = null,
					extPlayerLabel = null,
					separator = null,
					reloadLink = null,
					reloadLabel = null;
			
				phead = document.getElementById("player_head");
				if(!phead){
					console.error('id:"player_head not found."');
					return false;
				}
				
				/* 拡張プレイヤ、公式プレイヤの切り替えリンク表示 */
				extPlayerLink = document.createElement("a");
				extPlayerLabel = document.createTextNode("[非公式プレイヤーで表示(試験中)]");
				extPlayerLink.appendChild(extPlayerLabel);
				extPlayerLink.onclick = main.replaceFlashPlayer; // フラッシュのコメント再生プレイヤを拡張プレイヤに置換する
				extPlayerLink.href = location.href;
//				phead.appendChild(extPlayerLink);
				phead.firstElementChild.firstElementChild.firstElementChild.firstElementChild.appendChild(extPlayerLink);
				
				separator = document.createTextNode(" | ");
//				phead.appendChild(separator);
				phead.firstElementChild.firstElementChild.firstElementChild.firstElementChild.appendChild(separator);
				
				reloadLink = document.createElement("a");
				reloadLabel = document.createTextNode("[公式プレイヤーで表示]");
				reloadLink.appendChild(reloadLabel);
				reloadLink.onclick = location.reload;
				reloadLink.href = location.href;
				phead.appendChild(reloadLink);
				phead.firstElementChild.firstElementChild.firstElementChild.firstElementChild.appendChild(reloadLink);
				
			}else{
				console.error("log,live error.");
			}
			
			console.info("showed external player link.");
			return false;
		},
		
		
		/**
			@brief 再生ページのフラッシュプレイヤー "playerbox"を消し、拡張のプレイヤを表示する。
		*/
		replaceFlashPlayer : function(){
			var main = SATMAT_NICOJK.Nicojk.main;
			var pdiv = null,
				phead = null,
				phead_links = null,
				jknum = "",
				stTime = 0,
				enTime = 0,
				cntmng = null,
				msgbuf = null,
				cplayer = null,
				excanvas = null,
				debug_status_div = null,
				debug_static_status_div = null;
			
			
			pdiv = document.getElementById("playerbox");
			if(!pdiv){
				console.error('id:"playerbox" not found.');
				return false;
			}
			
			/* コメント再生用canvasの表示 */	
			excanvas = document.createElement("canvas");
			excanvas.id = "external_player";
			excanvas.width = "540";
			excanvas.height = "390";
			excanvas.style.cssFloat = "left";
			excanvas.style.marginRight = "6px";
			
			/* jk番号、開始時間、終了時間が書かれた文字列をプレイヤーページのアンカーから取得する
			　現在番組 例 : nicojk:jk1
			　過去番組 例 : nicojk:jk7&amp;start_time=1323104400&amp;end_time=1323106200
			 */
			phead = document.getElementById("player_head");
			if(!phead){
				console.error('id:"player_head" not found.');
				return false;
			}
			
			phead_links = phead.getElementsByTagName("a");
			if(phead_links.length==0){
				console.error('There are no name"a" tag.');
				return false;
			}
			
			for(var i=0; i<phead_links.length; i++){
				if(phead_links[i].href && phead_links[i].href.indexOf("nicojk:")>-1){
					var ancAry = null;
				
					console.log("jk href detail: " + phead_links[i].outerHTML + " " + phead_links[i].href);
					ancAry = phead_links[i].href.split('&');
					if(ancAry.length==1){								// 現在番組のとき
						jknum = ancAry[0].split(':')[1];				// jk[N]
						stTime = (new Date()).getTime()/1000;
						enTime = 0;
						break;
					}else if(ancAry.length>1){							// 過去番組のとき
						jknum = ancAry[0].split(':')[1];				// jk[N]
						stTime = parseInt( ancAry[1].split('=')[1] )	// start_time
						enTime = parseInt( ancAry[2].split('=')[1] )	// end_time	
						break;
					}
				}
			}
			
			/* jk番号が取得できなければ終了させる */
			if(jknum==""){
				console.error('There are no jk number.');
				return false;
			}
			
			/* 拡張プレイヤの置換処理 */
			pdiv.parentNode.replaceChild(excanvas, pdiv);
			externalPlayerDiv = excanvas;
			delete pdiv;
						
			debug_static_status_div = document.createElement("div");
			debug_static_status_div.id = "static_status_div";
			debug_static_status_div.style.fontSize = "6pt";
			excanvas.parentNode.insertBefore(
				debug_static_status_div, 
				excanvas.nextSibling.nextSibling
			); // "使い方,悪意のあるコメントを〜"のdivの前に追加

			debug_status_div = document.createElement("div");
			debug_status_div.id = "stat_div";
			debug_status_div.style.fontSize = "8pt";
			excanvas.parentNode.insertBefore(
				debug_status_div, 
				debug_static_status_div.nextSibling
			); // "使い方,悪意のあるコメントを〜"のdivの前に追加
			debug_status_div.nextSibling.style.cssClear = "both";
			
			msgbuf = SATMAT_NICOJK.Nicojk.CommentBuffer;
			cntmng = SATMAT_NICOJK.Nicojk.ConnectionManager;
			cntmng.setjkinfo(jknum, stTime, enTime);
			cntmng.setMsgBuf(msgbuf);
			cplayer = SATMAT_NICOJK.player;
			cplayer.init(msgbuf, stTime, enTime);			
			if(main.isLive()){
				cntmng.connectionStart();
			}else if(main.isLog()){
				cntmng.logConnectionStart();
			}else{
				console.error("main.isLive() or main.isLog() fatal error.");
				return false;
			}
						
			return false; // ページ遷移防止のためfalseを返す
		},
		
		/**
			@brief 刻々と変わるようなステータス表示
		*/
	 	setStatus: function(){
	 		var player = null,
	 			stat_div = null,
	 			start_date_ymd_str = "",
	 			mblen = 0;
	 			
	 		player = SATMAT_NICOJK.player;
	 		stat_div = document.getElementById("stat_div");
	 		if(!stat_div){
	 			console.error('There are no id:"stat_div"');
	 			return false;
	 		}
	 		
	 		start_date_ymd_str = player.date2str(player.msec2date());
	 		mblen = player.comment_buffer.length;
	 			
	 		stat_div.innerText = 'Interval timer count:' + player.timer_count + ' \r\n'
	 		+ 'Start time[ms,ymd]:' + player.event_start_date + ' ' + player.msec2dateYmdStr(player.event_start_date) + '\r\n'
	 		+ 'Elapsed time[ms]:' + player.play_elapsed_time + '\r\n'
	 		+ 'Playing time[ms,ymd] ' + player.play_past_time + ' ' + player.msec2dateYmdStr(player.play_past_time) + '\r\n'
	 		+ 'Comment buffer length:' + mblen + '\r\n'
	 		+ 'Comment count:' + player.comment_count + '\r\n\r\n';
	 	},
	 	
	 	/**
	 		@brief 頻繁には変わらないようなステータスの文字列を作成
	 	*/
	 	getStaticStatusString : function(){
	 		var jkmain = SATMAT_NICOJK.Nicojk.main,
	 			cntmng = SATMAT_NICOJK.Nicojk.ConnectionManager,
	 			jkinfo = null,
	 			flvinfo = null,
	 			threadinfo = null,
	 			elem = null,
	 			str = ""
	 		
	 		if(!jkmain && !cntmng){
	 			console.error("Module error. main or ConnectionManager is null.");
	 			return "";
	 		}
	 		
	 		jkinfo = cntmng.getjkinfo();
	 		flvinfo = cntmng.getFlvinfo();
	 		threadinfo = cntmng.getThreadinfo();
	 		
	 		str = "jkinfo.jk: " + jkinfo.jknum + "\r\n" +
	 			  " jkinfo.log_start_time: " + jkinfo.log_start_time + "\r\n" +
	 			  " jkinfo.log_end_time: " + jkinfo.log_end_time + "\r\n" +
	 			  " flvinfo.thread_id: " +  flvinfo.thread_id + "\r\n" +
	 			  " flvinfo.ms: " + flvinfo.ms + "\r\n" +
	 			  " flvinfo.http_port: " + flvinfo.http_port + "\r\n" +
	 			  " flvinfo.channel_no: " + flvinfo.channel_no + "\r\n" +
	 			  " flvinfo.channel_name: " + flvinfo.channel_name + "\r\n" +	 			  
	 			  " flvinfo.thread_base_time: " + flvinfo.thread_base_time + "\r\n" +
	 			  " flvinfo.thread_open_time: " + flvinfo.thread_open_time + "\r\n" +
	 			  " flvinfo.thread_start_time: " + flvinfo.thread_start_time + "\r\n" +
	 			  " flvinfo.thread_start_time: " + flvinfo.thread_start_time + "\r\n" +
	 			  " flvinfo.thread_end_time: " + flvinfo.thread_end_time + "\r\n" +
	 			  " flvinfo.user_id: " + flvinfo.user_id + "\r\n" +
	 			  " threadinfo.resultcode: " + threadinfo.resultcode + "\r\n" + 
	 			  " threadinfo.thread: " + threadinfo.thread + "\r\n" + 
	 			  " threadinfo.last_res: " + threadinfo.last_res + "\r\n" + 
	 			  " threadinfo.ticket: " + threadinfo.ticket + "\r\n" + 
	 			  " threadinfo.revision: " + threadinfo.revision + "\r\n" + 
	 			  " threadinfo.server_time: " + threadinfo.server_time + "\r\n";
	 		
	 		return str;
	 	},
	 	
	 	/**
	 		@brief 表示後は変わらないようなステータスを表示
	 	*/
	 	setStaticStatus: function(){
	 		var static_status_div = null;
	 		static_status_div = document.getElementById("static_status_div");
	 		if(!static_status_div){
	 			console.error('Therea are no id"static_status_div".');
	 			return false;
	 		}
	 		
	 		static_status_div.innerText = SATMAT_NICOJK.Nicojk.main.getStaticStatusString();
	 		return true;
	 	},
		
		/**
			@brief 現在番組コメントの表示ページならtrue
			@retval true 現在番組コメントの表示ページ
		*/
		isLive: function(){
			return location.href.indexOf('/watch/')>-1;
		},
		
		/**
			@brief 過去ログコメントの表示ページならtrue
			@retval true 過去ログコメントの表示ページ
		*/
		isLog: function(){
			return location.href.indexOf('/log/')>-1;
		}
	}
}());
